﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Battle
{
    public class BuffMgr_Normal : IBuffMgr
    {
        protected const int UpdateDeltaTime = 100;

        protected Dictionary<string, ST_ObjBuffData> dic_Buff;
        protected Dictionary<Type, object> dic_Obj; 

        public bool IsDestory { get; protected set; }

        protected IObjGetter objGetter;

        public BuffMgr_Normal(IObjGetter objGetter)
        {
            this.objGetter = objGetter;
            dic_Buff = new Dictionary<string, ST_ObjBuffData>();
            dic_Obj = new Dictionary<Type, object>();

            UpdataAsync();
        }
        public ST_ObjBuffData[] GetBuffDatas(string name)
        {
            if (IsDestory) return null;

            return dic_Buff.Values.TakeWhile((data) => data.strBuffName == name).ToArray();
        }

        public string AddBuff(ST_ObjBuffData buffData)
        {
            if (IsDestory) return string.Empty;

            var buffHandler = BuffHandlerMgr.GetBuffHandler(buffData.strBuffName);
            if (buffHandler!=null&& buffHandler.TryAddBuff(this, buffData) )
            {
                //如果没指定就自动生成一个
                if(string.IsNullOrEmpty(buffData.strGUID))
                    buffData.strGUID = GetGUID();

                if (!dic_Buff.ContainsKey(buffData.strGUID))
                {
                    dic_Buff.Add(buffData.strGUID, buffData);

                    buffHandler.OnBuffStart(this, buffData);
                }
                else
                    UnityEngine.Debug.LogError("buff guid 冲突");

                return buffData.strGUID;
            }
            else
                return string.Empty;
        }

        public void RemoveBuff(string guid)
        {
            if (IsDestory) return ;

            ST_ObjBuffData buffData;
            if (dic_Buff.TryGetValue(guid,out buffData))
            {
                dic_Buff.Remove(guid);
                BuffHandlerMgr.GetBuffHandler(buffData.strBuffName)?.OnBuffEnd(this, buffData);
            }
        }

        public void RemoveAllBuff(Func<ST_ObjBuffData, bool> check)
        {
            if (IsDestory) return ;

            if (check == null) return;

            List<string> listTmp = new List<string>();
            foreach (var item in dic_Buff.Values)
            {
                if (check(item))
                    listTmp.Add(item.strGUID);
            }

            for (int i = 0; i < listTmp.Count; i++)
            {
                RemoveBuff(listTmp[i]);
            }
        }

        protected async void UpdataAsync()
        {
            List<string> listEndBuffGUID = new List<string>();
            float deltaTime = UpdateDeltaTime / 1000f;

            Dictionary<string, List<ST_ObjBuffData>> dicTmp=new Dictionary<string, List<ST_ObjBuffData>>();

            while (!IsDestory)
            {
                //扣时间
                float time = UnityEngine.Time.time;
                foreach (var item in dic_Buff)
                {
                    if (item.Value.fBuffLife <= 0) continue;

                    if (item.Value.fBuffLife + item.Value.fBornTime < time)
                        listEndBuffGUID.Add(item.Key);
                }

                //执行 buff 的 Updata
                //TODO 需要优化
                #region 这里偷懒了
                dicTmp.Clear();
                foreach (var item in dic_Buff.Values)
                {
                    if (!dicTmp.ContainsKey(item.strBuffName))
                        dicTmp.Add(item.strBuffName, new List<ST_ObjBuffData>());

                    dicTmp[item.strBuffName].Add(item);
                }

                foreach (var item in dicTmp)
                {
                    var endBuffGUIDs = BuffHandlerMgr.GetBuffHandler(item.Key)?.OnUpdate(this, item.Value.ToArray(), deltaTime);
                    if(endBuffGUIDs!=null)
                    listEndBuffGUID.AddRange(endBuffGUIDs);
                }
                #endregion

                for (int i = 0; i < listEndBuffGUID.Count; i++)
                {
                    RemoveBuff(listEndBuffGUID[i]);
                }

                listEndBuffGUID.Clear();
                await Task.Delay(UpdateDeltaTime);
            }
        }

        protected string GetGUID()
        {
            return Guid.NewGuid().ToString();
        }

        public void DestorySelf()
        {
            if (IsDestory) return;

            dic_Buff.Clear();
            dic_Buff = null;

            IsDestory = true;
        }

        public T GetObj<T>() where T : class
        {
            if (IsDestory) return null;

            Type type = typeof(T);
            if (dic_Obj.ContainsKey(type))
                return dic_Obj[type] as T;

            if (objGetter != null)
            {
                T tmp = objGetter.GetObj<T>();

                dic_Obj.Add(type, tmp);

                return tmp;
            }
            else
                return null;
        }

        public void ChangeBuff(ST_ObjBuffData buffData)
        {
            if (IsDestory) return;

            if (dic_Buff.ContainsKey(buffData.strGUID))
                dic_Buff[buffData.strGUID] = buffData;
        }
    }
}
